<template>
  <inline-Modal
    :visible="visible"
    title="管理流程配置"
    :showOk="false"
    @cancel="cancelPage()"
  >
    <div class="config-flow-page-container">
      <div class="tools-container">
        <graph-config-container
          :graph="this.graph"
          @onSave="handleSave()"
        ></graph-config-container>
      </div>
      <div class="x6-container">
        <div id="stencil"></div>
        <div id="graph-container" ref="graph"></div>
        <div v-show="configVisibe" id="config-container">
          <node-config-container
            ref="nodeConfigContainer"
            v-show="isNode"
            :node="curNode"
            :dataList="dicCodeSource"
            @updateData="handleNode"
          ></node-config-container>
          <edge-config-container
            ref="EdgeConfigContainer"
            v-show="!isNode"
            :edge="curEdge"
            @updateData="handleEdge"
          ></edge-config-container>
          <span class="drawer-icon collpase" @click="handleCollpaseConfig">
            <a-icon type="double-right" />
          </span>
        </div>
        <span
          v-show="!configVisibe"
          class="drawer-icon open"
          @click="handleOpenConfig"
        >
          <a-icon type="double-left" />
        </span>
      </div>
    </div>
  </inline-Modal>
</template>

<script>
import { Graph, Shape, Addon } from "@antv/x6";
import "@antv/x6-vue-shape";
//边   编辑器
import EdgeConfigContainer from "./EdgeConfigContainer";
//节点 编辑器
import NodeConfigContainer from "./NodeConfigContainer";
//顶部 操作栏
import GraphConfigContainer from "./GraphConfigContainer";

import { getDicItemByCode } from "@/api/common.js";

import { updateFlowPath, detailFlowPath } from "@/api/knowledgeBase";
export default {
  components: {
    EdgeConfigContainer,
    NodeConfigContainer,
    GraphConfigContainer,
  },
  props: {
    visible: {
      type: Boolean,
      required: false,
    },
    configSource: {
      type: Object,
      default: () => {
        return {};
      },
    },
  },
  data() {
    return {
      graph: null,
      stencil: {},
      ports: {},
      curNode: {},
      curEdge: {},
      configVisibe: true,
      isNode: true,
      //节点字段
      dicCodeSource: [],
    };
  },
  watch: {
    visible: {
      handler(val) {
        this.$emit("update:visible", val);
        if (val) {
          this.$nextTick(() => {
            // 初始化画布
            this.initGraph();
            // 绑定画布快捷键
            this.graphBindKey();
            // 画布绑定监听事件
            this.graphOnEvent();
            // 初始化流程控件面板
            this.initStencil();
            // 初始化连接桩
            this.initPorts();
            // 渲染所有左侧控件图形
            this.loadStencil();
            // 初始化数据接口
            Promise.all([this.getNodeTextData(), this.getData()]);
          });
        }
      },
      immediate: true,
    },
  },
  methods: {
    getData() {
      let { proCode } = this.configSource;
      return new Promise((resolve, reject) => {
        detailFlowPath({ proCode })
          .then((res) => {
            let source = JSON.parse(res.data?.processContent ?? "[]") ?? [];
            // source.forEach((v) => {
            //   v.tools = [];
            // });
            this.$nextTick(() => {
              // 清空画布
              this.graph.clearCells();
              // 渲染节点数据
              this.graph.fromJSON({
                cells: source,
              });
            });
            resolve();
          })
          .catch((_) => {
            reject();
          })
          .finally((_) => {});
      });
    },

    //查询 节点 标题
    getNodeTextData() {
      return new Promise((resolve, reject) => {
        getDicItemByCode({ code: "approvalConstructionProcess" })
          .then((res) => {
            let { data } = res;
            this.dicCodeSource = data ?? [];
            resolve();
          })
          .catch((_) => {
            this.dicCodeSource = [];
            reject();
          })
          .finally((_) => {});
      });
    },

    //保存流程图
    handleSave() {
      let { proCode, uuid } = this.configSource;
      let { cells } = this.graph.toJSON();
      //   console.log("节点数据:", cells);
      //   console.log("proCode:", proCode);
      //   console.log("uuid:", uuid);
      if (cells.length == 0) {
        this.$message.info("请配置好流程图，在保存");
        return;
      }
      updateFlowPath({
        uuid,
        proCode,
        processContent: JSON.stringify(cells),
        //竣工验收
        type: "jgys",
      })
        .then((res) => {
          if (res.statusCode === 200 || res === 1) {
            this.$message.success("保存成功", 1.5);
            this.cancelPage();
          } else {
            this.$message.error(res?.message ?? "保存失败");
          }
        })
        .catch((_) => {});
    },

    // 初始化画布
    initGraph() {
      this.graph = new Graph({
        container: document.getElementById("graph-container"),
        grid: {
          // 绘制网格
          visible: true,
          // 指定网格类型
          type: "mesh",
          args: {
            color: "#ddd", // 网格线/点颜色
            thickness: 1, // 网格线宽度/网点大小
          },
        },
        async: true,
        //允许画布拖拽
        panning: {
          enabled: true,
          eventTypes: ["leftMouseDown", "mouseWheel"],
        },
        mousewheel: {
          enabled: true,
          zoomAtMousePosition: true,
          modifiers: "ctrl",
          minScale: 0.5,
          maxScale: 3,
        },
        connecting: {
          router: {
            name: "manhattan",
            args: {
              padding: 1,
            },
          },
          connector: {
            name: "rounded",
            args: {
              radius: 8,
            },
          },
          anchor: "center",
          connectionPoint: "anchor",
          allowBlank: false,
          snap: {
            radius: 20,
          },
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: "#8c8c8c",
                  strokeWidth: 1,
                  targetMarker: {
                    name: "block",
                    width: 8,
                    height: 6,
                  },
                },
              },
              tools: {
                name: "button-remove",
                args: { distance: -40 },
                rotate: true,
              },
              zIndex: 10,
            });
          },
          validateConnection({ targetMagnet }) {
            return !!targetMagnet;
          },
        },
        highlighting: {
          magnetAdsorbed: {
            name: "stroke",
            args: {
              attrs: {
                fill: "#5F95FF",
                stroke: "#5F95FF",
              },
            },
          },
        },
        resizing: false,
        rotating: true,
        selecting: {
          enabled: true,
          rubberband: false,
          showNodeSelectionBox: true,
        },
        snapline: true,
        keyboard: true,
        clipboard: true,
        history: true,
        //节点组
        embedding: {
          enabled: true,
          findParent({ node }) {
            const bbox = node.getBBox();
            return this.getNodes().filter((node) => {
              // 只有 data.parent 为 true 的节点才是父节点
              const data = node.getData();
              if (data && data.parent) {
                const targetBBox = node.getBBox();
                return bbox.isIntersectWithRect(targetBBox);
              }
              return false;
            });
          },
        },
        //限制节点组，子节点移动
        translating: {
          restrict(view) {
            const cell = view.cell;
            if (cell.isNode()) {
              const parent = cell.getParent();
              if (parent) {
                return parent.getBBox();
              }
            }
            return null;
          },
        },
      });
    },

    // 画布绑定监听事件
    graphOnEvent() {
      // 控制连接桩显示/隐藏
      const showPorts = (ports, show) => {
        for (let i = 0, len = ports.length; i < len; i = i + 1) {
          ports[i].style.visibility = show ? "visible" : "hidden";
        }
      };
      this.graph.on("node:mouseenter", () => {
        const container = document.getElementById("graph-container");
        const ports = container.querySelectorAll(".x6-port-body");
        showPorts(ports, true);
      });
      this.graph.on("node:mouseleave", () => {
        const container = document.getElementById("graph-container");
        const ports = container.querySelectorAll(".x6-port-body");
        showPorts(ports, false);
      });
      // 监听点击画布的节点
      this.graph.on("node:click", ({ e, x, y, node, view }) => {
        this.curNode = node;
        this.isNode = true;
      });
      // 监听画布添加节点动作
      this.graph.on("node:added", ({ node, index, options }) => {
        this.curNode = node;
        this.isNode = true;
        // todo 监听到画布添加了node之后，调后端接口创建一个接口
        // console.log("node:added", node);
        // let parent = node.getParent();
        // console.log(parent, "parent");
        // console.log(node.attrs.text.fontSize)
        // node.setLabel('xwtest') // 修改label的值
        // console.log('监听到拖入一个控件id：' + node.id)
        // console.log(this.graph.getNodes())
      });
      // 监听画布移除节点动作
      this.graph.on("node:removed", ({ node, index, options }) => {
        this.curNode = node;
        // console.log('node:removed')
        // console.log(node)
        this.$refs?.nodeConfigContainer?.resetForm();
      });

      // 监听节点之间连接动作
      this.graph.on("edge:added", ({ edge, index, options }) => {
        this.isNode = false;
        this.curEdge = edge;
        // todo 监听到连接线动作之后，调后端接口绑定关系
        // console.log('edge:added')
        // console.log(edge)
      });

      // 监听点击节点之间连接动作
      this.graph.on("edge:click", ({ e, x, y, edge, view }) => {
        this.isNode = false;
        this.curEdge = edge;
        // console.log("edge:click");
      });

      // 监听节点之间移除连接动作
      this.graph.on("edge:removed", ({ edge, index, options }) => {
        // todo 监听到连接线动作之后，调后端接口绑定关系
        // console.log("edge:removed");
        // console.log(edge)
        this.$refs?.EdgeConfigContainer?.resetForm();
      });

      // 边被选中时触发
      this.graph.on("edge:selected", ({ cell, edge, options }) => {
        this.isNode = false;
        this.curEdge = edge;
        this.curEdge.setAttrs({
          line: {
            stroke: "#1890ff",
          },
        });
      });
      //边被取消选中时触发
      this.graph.on("edge:unselected", ({ cell, edge, options }) => {
        this.isNode = false;
        this.curEdge = edge;
        this.curEdge.setAttrs({
          line: {
            stroke: "#8c8c8c",
          },
        });
      });
    },

    // 绑定画布快捷键
    graphBindKey() {
      this.graph.bindKey(["meta+c", "ctrl+c"], () => {
        const cells = this.graph.getSelectedCells();
        if (cells.length) {
          this.graph.copy(cells);
        }
        return false;
      });
      this.graph.bindKey(["meta+x", "ctrl+x"], () => {
        const cells = this.graph.getSelectedCells();
        if (cells.length) {
          this.graph.cut(cells);
        }
        return false;
      });
      this.graph.bindKey(["meta+v", "ctrl+v"], () => {
        if (!this.graph.isClipboardEmpty()) {
          const cells = this.graph.paste({ offset: 32 });
          this.graph.cleanSelection();
          this.graph.select(cells);
        }
        return false;
      });
      // undo redo
      this.graph.bindKey(["meta+z", "ctrl+z"], () => {
        if (this.graph.history.canUndo()) {
          this.graph.history.undo();
        }
        return false;
      });
      this.graph.bindKey(["meta+shift+z", "ctrl+shift+z"], () => {
        if (this.graph.history.canRedo()) {
          this.graph.history.redo();
        }
        return false;
      });
      // select all
      this.graph.bindKey(["meta+a", "ctrl+a"], () => {
        const nodes = this.graph.getNodes();
        if (nodes) {
          this.graph.select(nodes);
        }
      });
      // delete
      //   this.graph.bindKey("backspace", () => {
      //     const cells = this.graph.getSelectedCells();
      //     if (cells.length) {
      //       this.graph.removeCells(cells);
      //     }
      //   });

      // zoom
      this.graph.bindKey(["ctrl+1", "meta+1"], () => {
        const zoom = this.graph.zoom();
        if (zoom < 1.5) {
          this.graph.zoom(0.1);
        }
      });

      this.graph.bindKey(["ctrl+2", "meta+2"], () => {
        const zoom = this.graph.zoom();
        if (zoom > 0.5) {
          this.graph.zoom(-0.1);
        }
      });
    },

    // 初始化左侧流程控件面板
    initStencil() {
      this.stencil = new Addon.Stencil({
        title: "流程配置",
        target: this.graph,
        stencilGraphWidth: 250,
        // stencilGraphHeight: 250,
        collapsable: true,
        // notFoundText: "暂未匹配到结果",
        // placeholder: "搜索",
        // search: (cell, keyword, groupName, stencil) => {
        //   if (keyword) {
        //     return cell.label.includes(keyword);
        //   }
        //   return true;
        // },
        groups: [
          {
            title: "基础节点",
            name: "group1",
            graphHeight: 200,
            layoutOptions: {
              //   columns: 2,
              columns: 1,
              marginY: 50,
              marginX: 58,
            },
          },
          {
            title: "节点组",
            name: "group2",
            graphHeight: 300,
            layoutOptions: {
              columns: 1,
              marginY: 100,
              marginX: 58,
            },
          },
        ],
        // layoutOptions: {
        //   columns: 2,
        //   columnWidth: 110,
        //   rowHeight: 60,
        // },
      });
      document.getElementById("stencil").appendChild(this.stencil.container);
    },

    // 初始化链接桩
    initPorts() {
      this.ports = {
        groups: {
          top: {
            position: "top",
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: "#5F95FF",
                strokeWidth: 1,
                fill: "#fff",
                style: {
                  visibility: "hidden",
                },
              },
            },
          },
          right: {
            position: "right",
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: "#5F95FF",
                strokeWidth: 1,
                fill: "#fff",
                style: {
                  visibility: "hidden",
                },
              },
            },
          },
          bottom: {
            position: "bottom",
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: "#5F95FF",
                strokeWidth: 1,
                fill: "#fff",
                style: {
                  visibility: "hidden",
                },
              },
            },
          },
          left: {
            position: "left",
            attrs: {
              circle: {
                r: 4,
                magnet: true,
                stroke: "#5F95FF",
                strokeWidth: 1,
                fill: "#fff",
                style: {
                  visibility: "hidden",
                },
              },
            },
          },
        },
        items: [
          {
            group: "top",
          },
          {
            group: "right",
          },
          {
            group: "bottom",
          },
          {
            group: "left",
          },
        ],
      };
    },

    // 渲染所有左侧控件图形
    loadStencil() {
      Graph.registerNode(
        "custom-rect",
        {
          inherit: "rect",
          width: 210,
          height: 138,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: "#8A9295",
              fill: "#fff",
            },
            text: {
              fontSize: 18,
              fill: "#8c8c8c",
            },
          },
          ports: { ...this.ports },
          tools: [
            {
              rotate: true,
              name: "button-remove", // 工具名称
              args: { x: "100%", y: 0, offset: { x: -10, y: 10 } }, // 工具对应的参数
            },
          ],
        },
        true
      );

      Graph.registerNode(
        "custom-circle",
        {
          inherit: "circle",
          width: 210,
          height: 138,
          attrs: {
            body: {
              strokeWidth: 1,
              stroke: "#8A9295",
              fill: "#fff",
            },
            text: {
              fontSize: 12,
              fill: "#8c8c8c",
            },
          },
          ports: { ...this.ports },
          tools: [
            {
              rotate: true,
              name: "button-remove", // 工具名称
              args: { x: "100%", y: 0, offset: { x: -10, y: 10 } }, // 工具对应的参数
            },
          ],
        },
        true
      );

      const r1 = this.graph.createNode({
        shape: "custom-rect",
        label: undefined,
        attrs: {
          body: {
            rx: 18,
            ry: 26,
          },
        },
        zIndex: 5,
      });

      const r2 = this.graph.createNode({
        shape: "custom-rect",
        label: undefined,
        zIndex: 5,
      });

      const r3 = this.graph.createNode({
        shape: "custom-rect",
        attrs: {
          body: {
            rx: 6,
            ry: 6,
          },
        },
        label: undefined,
        zIndex: 5,
      });

      const r4 = this.graph.createNode({
        shape: "custom-circle",
        label: undefined,
        zIndex: 5,
      });

      const r5 = this.graph.createNode({
        shape: "custom-rect",
        label: undefined,
        zIndex: 1,
        width: 210,
        height: 250,
        attrs: {
          body: {
            strokeDasharray: 5.5,
            strokeWidth: 1,
            stroke: "#8A9295",
            fill: "transparent",
            rx: 0,
            ry: 0,
          },
        },
        data: {
          parent: true,
        },
      });

      this.stencil.load([r3], "group1");

      this.stencil.load([r5], "group2");
    },

    //更新边
    handleEdge(data) {
      this.curEdge = data;
    },

    // 更新node的数据
    handleNode(data) {
      this.curNode = data;
    },

    //返回
    cancelPage() {
      this.graph && this.graph.dispose();
      this.$parent.getTableData();
      this.$emit("update:visible", false);
    },

    // 收缩配置面板
    handleCollpaseConfig() {
      this.configVisibe = false;
    },

    // 展开配置面板
    handleOpenConfig() {
      this.configVisibe = true;
    },
  },
};
</script>

<style lang="less" scoped>
.modal-full-layout {
  /deep/.main {
    padding: 0;
  }
}
.config-flow-page-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  .tools-container {
    border-bottom: 1px solid #dfe3e8;
  }
  .x6-container {
    flex: 1;
    display: flex;
    position: relative;
    #stencil {
      width: 250px;
      height: 100%;
      position: relative;
      border-right: 1px solid #dfe3e8;
    }
    #graph-container {
      flex: 1;
    }
    #config-container {
      width: 250px;
      height: 100%;
      border-left: 1px solid #dfe3e8;
      position: relative;
    }
    .drawer-icon {
      width: 20px;
      height: 40px;
      border-radius: 50px 0 0 50px;
      line-height: 40px;
      text-align: center;
      border: 1px solid #1890ff;
      border-right: none;
      background-color: #1890ff;
      cursor: pointer;
      color: #fff;
      &.collpase {
        position: absolute;
        top: 50%;
        transform: translate(-50%);
        left: -10px;
      }
      &.open {
        position: absolute;
        top: 50%;
        transform: translate(-50%);
        right: -10px;
      }
    }

    /deep/.x6-widget-stencil {
      background-color: #fff;
    }
  }
}
</style>
